/*
** Mortem's HGE Addon 1.3
** Copyright (C) 2006-2007, Osokin 'elmortem' Makar
** http://elmortem.mirgames.ru
**
** User profile system.
*/

#include <mhaprofile.h>

#include <stdio.h>

HGE *mhaProfile::hge = 0;

mhaProfile::mhaProfile(void) {
	hge = hgeCreate(HGE_VERSION);
	User = new mhaList(true);
	FileName[0] = '\0';
	Reset();
}

mhaProfile::~mhaProfile(void) {
	delete User;
	hge->Release();
}

void mhaProfile::Clear(void) {
	User->Clear();
	SelUser = 0;
	Sel = -1;
}

void mhaProfile::Reset(void) {
	Clear();
}

bool mhaProfile::Load(const HGE_CHAR *filename) {
	Reset();

	if(!filename && !FileName) return false;
	if(filename && *filename) HGE_SCPY(FileName, filename);
	FILE * f = HGE_FOPEN_RB(FileName);
	if(!f) {
		if(Save(FileName)) {
			return Load(FileName);
		} else return false;
	}

	SelUser = 0;
	Sel = -1;
	mhaProfileUser *usr;
	mhaProfileVar *var;

	int userCount;
	fread(&userCount, 4, 1, f);

	int c, cc;
	for(int i = 0; i < userCount; i++) {
		usr = new mhaProfileUser();
		fread(&usr->Id, 4, 1, f);
		/*fread(&c, 4, 1, f);
		if(c > 0) {
			usr->Name = new HGE_CHAR[c + 1];
			fread(usr->Name, sizeof(HGE_CHAR), c, f);
			usr->Name[c] = (HGE_CHAR)L'\0';*/

		fread(&cc, 4, 1, f);
		for(int j = 0; j < cc; j++) {
			var = new mhaProfileVar();
			fread(&c, 4, 1, f);
			if(c > 0) {
				var->name = new HGE_CHAR[c + 1];
				fread(var->name, sizeof(HGE_CHAR), c, f);
				var->name[c] = '\0';
			}
			fread(&var->type, 4, 1, f);
			if(var->type == MHATYPE_INT) {
				fread(&var->iVal, 4, 1, f);
			} else if(var->type == MHATYPE_BOOL) {
				fread(&var->bVal, 1, 1, f);
			} else if(var->type == MHATYPE_FLOAT) {
				fread(&var->fVal, 4, 1, f);
			} else if(var->type == MHATYPE_STRING) {
				fread(&c, 4, 1, f);
				if(c > 0) {
					var->sVal = new HGE_CHAR[c + 1];
					fread(var->sVal, sizeof(HGE_CHAR), c, f);
					var->sVal[c] = '\0';
				}
			} else if(var->type == MHATYPE_USERDATA) {
				fread(&var->uValSize, 4, 1, f);
				if(var->uValSize > 0) {
					var->uVal = new BYTE[var->uValSize];
					fread(var->uVal, var->uValSize, 1, f);
				}
			}
			usr->Vars->AddLast(var);
			var = 0;
		}
		User->AddLast(usr);
		if(!SelUser) {
			SelUser = usr;
			Sel = i;
		}
		usr = 0;
		//}
	}
	fclose(f);
	return true;
}

bool mhaProfile::Save(const HGE_CHAR *filename) {
	if(!filename && !FileName) return false;
	if(filename && *filename) HGE_SCPY(FileName, filename);
	FILE * f = HGE_FOPEN_WB(FileName);
	if(!f) return false;
	int c;
	int userCount = User->Count();
	mhaProfileUser *usr;
	mhaProfileVar *var;

	fwrite(&userCount, 4, 1, f);

	User->Begin();
	usr = (mhaProfileUser*)User->Next();

	while(usr) {
		fwrite(&usr->Id, 4, 1, f);
		/*if(usr->Name) c = wcslen(usr->Name);
		else c = 0;
		fwrite(&c, 4, 1, f);
		if(c > 0) {
			fwrite(usr->Name, sizeof(HGE_CHAR), c, f);*/
			
		c = usr->Vars->Count();
		fwrite(&c, 4, 1, f);

		usr->Vars->Begin();
		var = (mhaProfileVar*)usr->Vars->Next();
		
		while(var) {
			if(var->name && *var->name) c = HGE_SLEN(var->name);
			else c = 0;
			fwrite(&c, 4, 1, f);
			if(c) fwrite(var->name, sizeof(HGE_CHAR), c, f);
			fwrite(&var->type, 4, 1, f);
			if(var->type == MHATYPE_INT) {
				fwrite(&var->iVal, 4, 1, f);
			} else if(var->type == MHATYPE_BOOL) {
				fwrite(&var->bVal, 1, 1, f);
			} else if(var->type == MHATYPE_FLOAT) {
				fwrite(&var->fVal, 4, 1, f);
			} else if(var->type == MHATYPE_STRING) {
				if(var->sVal) c = HGE_SLEN(var->sVal);
				else c = 0;
				fwrite(&c, 4, 1, f);
				if(c > 0) fwrite(var->sVal, sizeof(HGE_CHAR), c, f);
			} else if(var->type == MHATYPE_USERDATA) {
				fwrite(&var->uValSize, 4, 1, f);
					if(var->uValSize > 0) {
						fwrite(var->uVal, var->uValSize, 1, f);
					}
			}

			var = (mhaProfileVar*)usr->Vars->Next();
		}
		//}
		usr = (mhaProfileUser*)User->Next();
	}

	fclose(f);
	return true;
}

void mhaProfile::DumpToLog(void) {
	int c;
	int userCount = User->Count();
	mhaProfileUser *usr;
	mhaProfileVar *var;

	hge->System_Log(TXT("MHA Profile Dump:"));
	hge->System_Log(TXT("Profile Count: %d"), userCount);

	User->Begin();
	usr = (mhaProfileUser*)User->Next();

	while(usr) {
		hge->System_Log(TXT("\tID: %d"), usr->Id);
		c = usr->Vars->Count();
		usr->Vars->Begin();
		var = (mhaProfileVar*)usr->Vars->Next();
		
		while(var) {
			if(var->name && *var->name) c = HGE_SLEN(var->name);
			else c = 0;
			if(c) hge->System_Log(TXT("\t%s = "), var->name);
			if(var->type == MHATYPE_INT) {
				hge->System_Log(TXT("\t\t%d"), var->iVal);
			} else if(var->type == MHATYPE_BOOL) {
				hge->System_Log(TXT("\t\t%s"), (var->bVal) ? TXT("True") : TXT("False"));
			} else if(var->type == MHATYPE_FLOAT) {
				hge->System_Log(TXT("\t\t%f"), var->fVal);
			} else if(var->type == MHATYPE_STRING) {
				if(var->sVal) c = HGE_SLEN(var->sVal);
				else c = 0;
				if(c > 0) hge->System_Log(TXT("\t\t'%s'"), var->sVal);
				else hge->System_Log(TXT("\t\t''"));
			} else if(var->type == MHATYPE_USERDATA) {
				hge->System_Log(TXT("\t\tUSERDATA"));
			}

			var = (mhaProfileVar*)usr->Vars->Next();
		}
		//}
		hge->System_Log(TXT("\t---"));
		usr = (mhaProfileUser*)User->Next();
	}
}

void mhaProfile::Add(int id) {
	if(!_findUser(id)) _addUser(id, 0);
}

int mhaProfile::Select(int id) {
	if(id == -2) return Sel;
	if(id < 0) {
		SelUser = 0;
		Sel = -1;
		return -1;
	}
	SelUser = _findUser(id);
	if(!SelUser) {
		SelUser = _addUser(id, TXT("Player"));
	}
	Sel = id;
	return Sel;
}

bool mhaProfile::Is(int id) {
	if(id < 0) id = Sel;
	if(id < 0) return false;
	if(!_findUser(id)) return false;
	return true;
}

void mhaProfile::Remove(int id) {
	if(id < 0) id = Sel;
	if(id < 0) return;
	mhaProfileUser *usr = _findUser(id);
	if(usr) User->Remove(usr);
	if(Sel == id) {
		Sel = -1;
		SelUser = 0;
	}
}

void mhaProfile::setInt(const HGE_CHAR *varname, int val, int id) {
	if(!varname || !*varname) return;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return;
	mhaProfileVar *var = _addVar(usr->Vars, varname);
	var->type = MHATYPE_INT;
	var->iVal = val;
}

void mhaProfile::setBool(const HGE_CHAR *varname, bool val, int id) {
	if(!varname || !*varname) return;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return;
	mhaProfileVar *var = _addVar(usr->Vars, varname);
	var->type = MHATYPE_BOOL;
	var->bVal = val;
}

void mhaProfile::setFloat(const HGE_CHAR *varname, float val, int id) {
	if(!varname || !*varname) return;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return;
	mhaProfileVar *var = _addVar(usr->Vars, varname);
	var->type = MHATYPE_FLOAT;
	var->fVal = val;
}

void mhaProfile::setString(const HGE_CHAR *varname, const HGE_CHAR *val, int id) {
	if(!varname || !*varname) return;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return;
	mhaProfileVar *var = _addVar(usr->Vars, varname);
	if(!val || !*val) return;
	var->type = MHATYPE_STRING;
	var->sVal = new HGE_CHAR[HGE_SLEN(val) + 1];
	HGE_SCPY(var->sVal, val);
}

void mhaProfile::setUserdata(const HGE_CHAR *varname, void *val, int size, int id) {
	if(!varname || !*varname) return;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return;
	mhaProfileVar *var = _addVar(usr->Vars, varname);
	if(!val) return;
	var->type = MHATYPE_USERDATA;
	var->uVal = new HGE_CHAR[size];
	memcpy(var->uVal, val, size);
	var->uValSize = size;
}

int mhaProfile::getInt(const HGE_CHAR *varname, int id) {
	if(!varname || !*varname) return 0;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return 0;
	mhaProfileVar *var = _findVar(usr->Vars, varname);
	if(!var || var->type != MHATYPE_INT) return 0;
	return var->iVal;
}

bool mhaProfile::getBool(const HGE_CHAR *varname, int id) {
	if(!varname || !*varname) return false;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return false;
	mhaProfileVar *var = _findVar(usr->Vars, varname);
	if(!var || var->type != MHATYPE_BOOL) return false;
	return var->bVal;
}

float mhaProfile::getFloat(const HGE_CHAR *varname, int id) {
	if(!varname || !*varname) return 0.f;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return 0.f;
	mhaProfileVar *var = _findVar(usr->Vars, varname);
	if(!var || var->type != MHATYPE_FLOAT) return 0.f;
	return var->fVal;
}

HGE_CHAR *mhaProfile::getString(const HGE_CHAR *varname, int id) {
	if(!varname || !*varname) return 0;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return 0;
	mhaProfileVar *var = _findVar(usr->Vars, varname);
	if(!var || var->type != MHATYPE_STRING) return 0;
	return var->sVal;
}

void *mhaProfile::getUserdata(const HGE_CHAR *varname, int id) {
	if(!varname || !*varname) return 0;
	mhaProfileUser* usr;
	if(id < 0) usr = SelUser;
	else usr = _findUser(id);
	if(!usr) return 0;
	mhaProfileVar *var = _findVar(usr->Vars, varname);
	if(!var || var->type != MHATYPE_USERDATA || var->uValSize <= 0) return 0;
	return var->uVal;
}

void mhaProfile::setName(const HGE_CHAR *name, int id) {
	setString(TXT("_PLAYERNAME_"), name, id);
}

HGE_CHAR *mhaProfile::getName(int id) {
	return getString(TXT("_PLAYERNAME_"), id);
}

// ===

mhaProfileUser *mhaProfile::_findUser(int id) {
	User->Begin();
	mhaProfileUser *usr = (mhaProfileUser*)User->Next();
	while(usr) {
		if(usr->Id == id) return usr;
		usr = (mhaProfileUser*)User->Next();
	}
	return 0;
}

mhaProfileUser *mhaProfile::_addUser(int id, const HGE_CHAR *name) {
	mhaProfileUser *usr = new mhaProfileUser();
	usr->Id = id;
	mhaProfileUser *old = SelUser;
	User->AddLast(usr);
	setName(name, id);
	return usr;
}

mhaProfileVar *mhaProfile::_findVar(mhaList *vars, const HGE_CHAR *varname) {
	vars->Begin();
	mhaProfileVar *var = (mhaProfileVar*)vars->Next();
	while(var) {
		if(!HGE_SCMP(var->name, varname)) return var;
		var = (mhaProfileVar*)vars->Next();
	}
	return 0;
}

mhaProfileVar *mhaProfile::_addVar(mhaList *vars, const HGE_CHAR *varname) {
	mhaProfileVar *var = _findVar(vars, varname);
	if(!var) {
		var = new mhaProfileVar();
		var->name = new HGE_CHAR[HGE_SLEN(varname) + 1];
		HGE_SCPY(var->name, varname);
		vars->AddLast(var);
	} else {
		if(var->type == MHATYPE_STRING) {
			if(var->sVal && var->sVal) delete var->sVal;
			var->sVal = 0;
		} else if(var->type == MHATYPE_USERDATA) {
			if(var->uValSize > 0) {
				delete var->uVal;
				var->uValSize = 0;
			}
		}
		var->type = MHATYPE_INT;
	}

	return var;
}
